package com.ning.parking.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.BetweenFormatter;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ning.parking.domain.ParkingLotWhitelist;
import com.ning.parking.domain.ParkingRecord;
import com.ning.parking.domain.VO.BillingTimeVO;
import com.ning.parking.domain.VO.Pagination;
import com.ning.parking.domain.dto.ParkingLotWhitelistCarLicenseEntity;
import com.ning.parking.domain.dto.ParkingLotWhitelistPageDto;
import com.ning.parking.domain.dto.ParkingLotWhitelistSaveUpdateDTO;
import com.ning.parking.service.ParkingLotMonthlyApplyService;
import com.ning.parking.service.ParkingLotWhitelistService;
import com.ning.parking.mapper.ParkingLotWhitelistMapper;
import com.scsonic.common.enums.caryardmanage.PeriodValidityTypeEnum;
import com.scsonic.common.enums.parking.ParkingCarTypeEnum;
import com.scsonic.framework.exception.BizException;
import com.scsonic.framework.util.DateUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 *
 */
@Slf4j
@Service
@AllArgsConstructor
public class ParkingLotWhitelistServiceImpl extends ServiceImpl<ParkingLotWhitelistMapper, ParkingLotWhitelist> implements ParkingLotWhitelistService{
    private final ParkingLotMonthlyApplyService parkingLotMonthlyApplyService;
    private final ParkingLotMonthlyApplyService parkingLotWhiteListCarLicenseService;


    @Override
    public ParkingLotWhitelist saveOrUpdateWhitelist(ParkingLotWhitelistSaveUpdateDTO dto) {
        log.info("白名单 保存修改:{}", JSONUtil.toJsonStr(dto));
        checkCarLicense(dto);
        ParkingLotWhitelist whitelist = BeanUtil.copyProperties(dto, ParkingLotWhitelist.class);

        //车牌
        List<ParkingLotWhitelistCarLicenseEntity> licenseEntities = BeanUtil.copyToList(dto.getCarLicenses(), ParkingLotWhitelistCarLicenseEntity.class);

        //删除之前车牌
        if (Objects.nonNull(dto.getWhitelistId())) {
            parkingLotWhiteListCarLicenseService.removeById(dto.getWhitelistId());
        }

        //新增或者修改
        saveOrUpdate(whitelist);

        //赋值白名单 id
        licenseEntities.forEach(item -> {
            item.setWhitelistId(whitelist.getWhitelistId());
        });

        //车牌信息
        parkingLotWhiteListCarLicenseService.saveBatchs(licenseEntities);

        //新增或者修改预警车辆
//        dto.setId(whitelist.getId());
//        saveOrUpdateCarWarning(dto);
        return whitelist;
    }

    private void checkCarLicense(ParkingLotWhitelistSaveUpdateDTO dto) {
        List<ParkingLotWhitelist> list = lambdaQuery().eq(ParkingLotWhitelist::getCarLicense, dto.getCarLicense()).list();
        if (ObjectUtil.isNotEmpty(list) && list.size() > 0){
            throw new BizException(dto.getCarLicense()+"白名单存在");
        }
    }

    @Override
    public ParkingLotWhitelist saveWhitelist(ParkingLotWhitelist parkingLotBaseInfo) {
        saveOrUpdate(parkingLotBaseInfo);
        return parkingLotBaseInfo;
    }

    @Override
    public Pagination<ParkingLotWhitelist> selectPage(ParkingLotWhitelistPageDto pageBase) {
        //小于 大于
        Page<ParkingLotWhitelist> page = lambdaQuery()
                .like(ObjectUtil.isNotEmpty(pageBase.getCarLicense()), ParkingLotWhitelist::getCarLicense, pageBase.getCarLicense())
                .lt(ObjectUtil.isNotEmpty(pageBase.getStartTime()), ParkingLotWhitelist::getStartTime, pageBase.getStartTime())
                .gt(ObjectUtil.isNotEmpty(pageBase.getEndTime()), ParkingLotWhitelist::getEndTime, pageBase.getEndTime())
                .orderByDesc(ParkingLotWhitelist::getWhitelistId).page(pageBase.toPage());
        return Pagination.of(page);
    }

    @Override
    public ParkingLotWhitelist selectWhitlist(String carLicense, Date captureTime, Long parkingLotId) {
        ParkingLotWhitelist one = lambdaQuery()
                .eq(ParkingLotWhitelist::getCarLicense, carLicense)
                .eq(ParkingLotWhitelist::getParkingLotId, parkingLotId)
//                .gt(ParkingLotWhitelist::getStartTime, captureTime)
//                .lt(ParkingLotWhitelist::getEndTime, captureTime)
                .orderByDesc(ParkingLotWhitelist::getStartTime)
                .last("limit 1")
                .one();
        if (one==null){
            return one;
        }
        if (one.getPrescription() != null &&  one.getPrescription()== PeriodValidityTypeEnum.FOREVER) {
            return one;
        }

        Date startTime = one.getStartTime();
        Date endTime = new Date(one.getEndTime().getTime()+(1000*60*60*24));

        if (startTime==null||endTime==null){
            return null;
        }

        if (startTime.getTime() <= captureTime.getTime() && endTime.getTime() >= captureTime.getTime()) {
            return one;
        }
        return null;
    }

    @Override
    public BillingTimeVO selectWhitelistRecord(ParkingRecord record) {
        List<ParkingLotWhitelist> whitelists =  this.baseMapper.selectParkingLotWhitelist(record.getCarLicense(),record.getEntTime(),record.getParkingLotId());

        BillingTimeVO billingTimeVO = new BillingTimeVO();
        //白名单
        if (ObjectUtil.isEmpty(whitelists)) {
            return parkingLotMonthlyApplyService.selectMonthlyRecord(record);
        }

        ParkingLotWhitelist parkingLotWhitelist = whitelists.get(0);


        String led = record.getCarLicense()+"免费车祝您一路顺风";

        if (parkingLotWhitelist.getPrescription() == PeriodValidityTypeEnum.FOREVER) {
            record.setLedShow(led);
            billingTimeVO.setParkingCarType(ParkingCarTypeEnum.WHITELIST);
            return billingTimeVO;
        }

        DateTime exitTimeYMH =  DateUtils.date(record.getExitTime());
        exitTimeYMH.setField(DateField.MILLISECOND,0);
        exitTimeYMH.setField(DateField.SECOND,0);
        exitTimeYMH.setField(DateField.HOUR_OF_DAY,0);
        exitTimeYMH.setField(DateField.MINUTE,0);

        Date startTime = parkingLotWhitelist.getStartTime();
        Date endTime = parkingLotWhitelist.getEndTime();
        //月租完全包含
        if (endTime.getTime()>=exitTimeYMH.getTime() && startTime.getTime() <= record.getEntTime().getTime() ){
            record.setLedShow(led);
            billingTimeVO.setParkingCarType(ParkingCarTypeEnum.WHITELIST);
            return billingTimeVO;
        }

        //月租超停
        if (whitelists.size() == 1){
            if (startTime.getTime() < exitTimeYMH.getTime()){
                DateTime endDay = DateUtils.date(endTime);
                //结束时间是从00点-24 需要增加一天
                endDay.setField(DateField.DAY_OF_YEAR,endDay.getField(DateField.DAY_OF_YEAR)+1);
                Long exitMs = record.getExitTime().getTime() - endDay.getTime();
                log.info("总-超停时长:{}", DateUtil.formatBetween(record.getExitTime(), endDay, BetweenFormatter.Level.SECOND));
                record.setRemark("超停时长"+DateUtil.formatBetween(record.getExitTime(), endDay, BetweenFormatter.Level.SECOND));
                Date exitTime = new Date(record.getEntTime().getTime() + exitMs);
                billingTimeVO.setParkingCarType(ParkingCarTypeEnum.COMMON);
                billingTimeVO.setEntTime(record.getEntTime());
                billingTimeVO.setExitTime(exitTime);
                return billingTimeVO;
            }else {
                long exitMs = startTime.getTime() - exitTimeYMH.getTime();
                Date exitTime = new Date(record.getEntTime().getTime() + exitMs);
                billingTimeVO.setParkingCarType(ParkingCarTypeEnum.COMMON);
                billingTimeVO.setEntTime(record.getEntTime());
                billingTimeVO.setExitTime(exitTime);
                return billingTimeVO;
            }
        }

        //多次续租累积后
        Long exitMs = 0L;
        //必须少循环一层不然会出数组越界 稳妥起见循环之后处理最后一次
        for (int i = 0; i < whitelists.size()-1; i++) {
            ParkingLotWhitelist parkingLotMonthlyApplyAf = whitelists.get(i);
            if (parkingLotMonthlyApplyAf.getPrescription() == PeriodValidityTypeEnum.FOREVER) {
                continue;
            }
            //开始时间比较
            if (i==0){
                Date start = parkingLotMonthlyApplyAf.getStartTime();
                Date entTime = record.getEntTime();
                if (entTime.getTime() < start.getTime()) {
                    log.info("超停时长:{}", DateUtil.formatBetween(start, entTime, BetweenFormatter.Level.SECOND));
                    record.setRemark("超停时长"+DateUtil.formatBetween(start, entTime, BetweenFormatter.Level.SECOND));
                    exitMs += start.getTime() - entTime.getTime();
                }
            }

            DateTime endDay = DateUtils.date(parkingLotMonthlyApplyAf.getEndTime());
            //结束时间是从00点-24 需要增加一天
            endDay.setField(DateField.DAY_OF_YEAR,endDay.getField(DateField.DAY_OF_YEAR)+1);
            long exitPoor = record.getExitTime().getTime() - endDay.getTime();

            //月租结束大于出场结束
            if (exitPoor < 0){
                billingTimeVO.setEntTime(record.getEntTime());
                if (exitMs<=0) {
                    record.setLedShow(record.getCarLicense()+"月租车辆祝您一路顺风");
                    billingTimeVO.setParkingCarType(ParkingCarTypeEnum.MONTHLY);
                    return billingTimeVO;
                }
                billingTimeVO.setParkingCarType(ParkingCarTypeEnum.COMMON);
                Date exitTime = new Date(record.getEntTime().getTime() + exitMs);
                billingTimeVO.setExitTime(exitTime);
                log.info("总-超停时长:{}", DateUtil.formatBetween(exitTime, record.getEntTime(), BetweenFormatter.Level.SECOND));
                record.setRemark("超停时长"+DateUtil.formatBetween(exitTime, record.getEntTime(), BetweenFormatter.Level.SECOND));
                return billingTimeVO;
            }

            ParkingLotWhitelist parkingLotMonthlyApplyBe = whitelists.get(i+1);
            DateTime endDayAf = DateUtils.date( parkingLotMonthlyApplyAf.getStartTime());
            DateTime startDayBe = DateUtils.date( parkingLotMonthlyApplyBe.getStartTime());
            //结束时间是从00点-24 需要增加一天
            endDayAf.setField(DateField.DAY_OF_YEAR,endDayAf.getField(DateField.DAY_OF_YEAR)+1);
            long poor = startDayBe.getTime() -endDayAf.getTime();
            if (poor > 0) {
                log.info("超停时长:{}", DateUtil.formatBetween(endDayAf, startDayBe, BetweenFormatter.Level.SECOND));
                record.setRemark("超停时长"+DateUtil.formatBetween(endDayAf, startDayBe, BetweenFormatter.Level.SECOND));
                exitMs =+ poor;
            }
        }

        ParkingLotWhitelist parkingLotMonthlyApply = whitelists.get(whitelists.size() - 1);
        if (parkingLotMonthlyApply.getPrescription() != PeriodValidityTypeEnum.FOREVER) {
            DateTime endDay = DateUtils.date(parkingLotMonthlyApply.getEndTime());
            //结束时间是从00点-24需要增加一天
            endDay.setField(DateField.DAY_OF_YEAR,endDay.getField(DateField.DAY_OF_YEAR)+1);
            long poor = record.getExitTime().getTime() - endDay.getTime();
            if (poor > 0) {
                log.info("超停时长:{}", DateUtil.formatBetween(record.getExitTime(), endDay, BetweenFormatter.Level.SECOND));
                record.setRemark("超停时长"+DateUtil.formatBetween(record.getExitTime(), endDay, BetweenFormatter.Level.SECOND));
                exitMs += poor;
            }
        }

        if (exitMs>0){
            Date exitTime = new Date(record.getEntTime().getTime() + exitMs);
            log.info("总-超停时长:{}", DateUtil.formatBetween(exitTime, record.getEntTime(), BetweenFormatter.Level.SECOND));
            record.setRemark("超停时长"+DateUtil.formatBetween(exitTime, record.getEntTime(), BetweenFormatter.Level.SECOND));
            billingTimeVO.setParkingCarType(ParkingCarTypeEnum.COMMON);
            billingTimeVO.setEntTime(record.getEntTime());
            billingTimeVO.setExitTime(exitTime);
        }else {
            billingTimeVO.setParkingCarType(ParkingCarTypeEnum.WHITELIST);
        }

        return billingTimeVO;
    }
}




